#ifndef GDN_MANAGER_H
#define GDN_MANAGER_H

#include <string>
#include <map>
#include <iostream>

namespace gdn
{
	// Grr, can't get the functions being const to work how I want it...

	template< class RES_TYPE >
	class Manager
	{
		public:
			Manager();
			virtual ~Manager();


			virtual void Load( const std::string& resName );
			virtual bool IsLoaded( const std::string& resName );
			virtual void Unload( const std::string& resName );

			virtual void LoadAll();
			virtual void UnloadAll();


			virtual void AddResource( const std::string& resName, RES_TYPE* resource = NULL );
			RES_TYPE* GetResource( const std::string& resName );
			virtual void RemoveResource( const std::string& resName );

			virtual bool DoesResourceExist( const std::string& resName );

		protected:
			std::map< std::string, RES_TYPE* > resources;

			virtual typename std::map< std::string, RES_TYPE* >::iterator GetResourceIterator( const std::string& resName );
	};

	template< class RES_TYPE >
	Manager< RES_TYPE >::Manager()
	{
		// I think I will need this, but I can't think of what for...
	}

	template< class RES_TYPE >
	Manager< RES_TYPE >::~Manager()
	{
		UnloadAll();
	}

	template< class RES_TYPE >
	void Manager< RES_TYPE >::Load( const std::string& resName )
	{
		//std::cout << "load " << resName << std::endl;
		if ( IsLoaded( resName ) )
		{
			return;
		}

		// To do: Get around this dirty hack.
		// ie. Less laziness! :P
		RES_TYPE* res = new RES_TYPE;
		GetResourceIterator( resName )->second = res;

		// To do: Get around this little hack of hard-coding LoadFromFile.
		// How would I do this, though?
		res->LoadFromFile( resName );
	}

	template< class RES_TYPE >
	bool Manager< RES_TYPE >::IsLoaded( const std::string& resName )
	{
		if ( !GetResource( resName ) )
		{
			return false;
		}
		return true;
	}

	template< class RES_TYPE >
	void Manager< RES_TYPE >::Unload( const std::string& resName )
	{
		if ( !IsLoaded( resName ) )
		{
			return;
		}

		delete GetResource( resName );
	}

	template< class RES_TYPE >
	void Manager< RES_TYPE >::LoadAll()
	{
		for ( typename std::map< std::string, RES_TYPE* >::iterator it = resources.begin(); it != resources.end(); ++it )
		{
			Load( it->first );
		}
	}

	template< class RES_TYPE >
	void Manager< RES_TYPE >::UnloadAll()
	{
		for ( typename std::map< std::string, RES_TYPE* >::iterator it = resources.begin(); it != resources.end(); ++it )
		{
			Unload( it->first );
		}
	}

	template< class RES_TYPE >
	void Manager< RES_TYPE >::AddResource( const std::string& resName, RES_TYPE* resource )
	{
		resources.insert( std::pair< std::string, RES_TYPE* >( resName, resource ) );
	}

	template< class RES_TYPE >
	RES_TYPE* Manager< RES_TYPE >::GetResource( const std::string& resName )
	{
		//std::cout << "get";
		if ( GetResourceIterator( resName ) == resources.end() )
		{
			return NULL;
		}
		return GetResourceIterator( resName )->second;
	}

	template< class RES_TYPE >
	void Manager< RES_TYPE >::RemoveResource( const std::string& resName )
	{
		if ( GetResourceIterator( resName ) != resources.end() )
		{
			resources.erase( GetResourceIterator( resName ) );
		}
	}

	template< class RES_TYPE >
	bool Manager< RES_TYPE >::DoesResourceExist( const std::string& resName )
	{
		if ( GetResourceIterator( resName ) == resources.end() )
		{
			return false;
		}
		return true;
	}

	template< class RES_TYPE >
	typename std::map< std::string, RES_TYPE* >::iterator Manager< RES_TYPE >::GetResourceIterator( const std::string& resName )
	{
		return resources.find( resName );
	}
}

#endif // GDN_MANAGER_H
